home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 4 / Apprentice-Release4.iso / Source Code / Add-Ons / MPW / MPW cawf 4.0.9 / cawf.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-12-01  |  15.9 KB  |  726 lines  |  [TEXT/KAHL]

  1. /*
  2.  *    cawf - a C version of Henry Spencer's awf(1), the Amazingly
  3.  *           Workable (text) Formatter
  4.  *
  5.  *    V. Abell, Purdue University Computing Center
  6.  */
  7.  
  8. /*
  9.  *    Copyright (c) 1991 Purdue University Research Foundation,
  10.  *    West Lafayette, Indiana 47907.  All rights reserved.
  11.  *
  12.  *    Written by Victor A. Abell <abe@cc.purdue.edu>,  Purdue    University
  13.  *    Computing Center.  Not derived from licensed software; derived from
  14.  *    awf(1) by Henry Spencer of the University of Toronto.
  15.  *
  16.  *    Permission is granted to anyone to use this software for any
  17.  *    purpose on any computer system, and to alter it and redistribute
  18.  *    it freely, subject to the following restrictions:
  19.  *
  20.  *    1. The author is not responsible for any consequences of use of
  21.  *       this software, even if they arise from flaws in it.
  22.  *
  23.  *    2. The origin of this software must not be misrepresented, either
  24.  *       by explicit claim or by omission.  Credits must appear in the
  25.  *       documentation.
  26.  *
  27.  *    3. Altered versions must be plainly marked as such, and must not
  28.  *       be misrepresented as being the original software.  Credits must
  29.  *       appear in the documentation.
  30.  *
  31.  *    4. This notice may not be removed or altered.
  32.  */
  33.  
  34. static char Version[] = "4.09";
  35.  
  36. #include "cawf.h"
  37.  
  38. #include <time.h>
  39.  
  40. #include <sys/stat.h>
  41.  
  42. #if    !defined(UNIX)
  43. #include <io.h>
  44. #include <process.h>
  45. #include <string.h>
  46. #include <sys\types.h>
  47. #include <sys\stat.h>
  48. #endif    /* !defined(UNIX) */
  49.  
  50. #if    defined(macintosh)
  51.  
  52. # if    !defined(CAWFLIB)
  53. #define    MACINTFCAWF    "Interfaces:cawf:"
  54. # endif    /* !defined(CAWFLIB) */
  55.  
  56. extern void InitToolbox();
  57. #endif    /* defined(macintosh) */
  58.  
  59. static char *Month[] =
  60.     { "January", "February", "March", "April", "May", "June", "July",
  61.       "August", "September", "October", "November", "December" };
  62.  
  63.  
  64. main(argc, argv)
  65.     int     argc;
  66.     char    *argv[];
  67. {
  68.     char dt[32];            /* date for td and DY strings */
  69.     char *ep;                   /* environment pointer */
  70.     int fff = 0;            /* final form feed status */
  71.     char *files[MAXFILES];      /* file names */
  72.     int help = 0;            /* help status */
  73.     int i;                           /* temporary index */
  74.     size_t l;                       /* length */
  75.     char *lib = CAWFLIB;        /* library path */
  76.     int libl;            /* library path length */
  77.     struct tm *lt;            /* local time structure pointer */
  78.     int mac = 0;            /* macro specification status */
  79.     int nf = 0;                 /* number of files */
  80.     char *np;                   /* name pointer */
  81.     int pc;                     /* prolog count */
  82.     struct stat sbuf;               /* stat buffer */
  83.     time_t tm;            /* system time of day */
  84. /*
  85.  * Save program name.
  86.  */
  87.     if ((Pname = strrchr(argv[0], '\\')) != NULL)
  88.         Pname++;
  89.     else if ((Pname = strrchr(argv[0], '/')) != NULL)
  90.         Pname++;
  91.     else
  92.         Pname = argv[0];
  93.  
  94. #if    defined(macintosh)
  95. /*
  96.  * Perform Macintosh initialization.
  97.  */
  98.     InitToolbox();
  99.  
  100. # if    !defined(CAWFLIB)
  101.     if ((ep = getenv("MPW")) == NULL)
  102.         ep = "";
  103.     if ((CAWFLIB = (char *)malloc(strlen(ep) + strlen(MACINTFCAWF) + 1))
  104.     == NULL) {
  105.         (void) fprintf(stderr,
  106.             "%s: no CAWFLIB buffer space for \"%s%s\"\n",
  107.             Pname, ep, MACINTFCAWF);
  108.         exit(1);
  109.     }
  110.     (void) sprintf(CAWFLIB, "%s%s", ep, MACINTFCAWF);
  111.     lib = CAWFLIB;
  112. # endif    /* !defined(CAWFLIB) */
  113. #endif    /* defined(macintosh) */
  114.  
  115.  
  116. #if    defined(__EMX__)
  117. /*
  118.  * Perform OS2 initialization:
  119.  *
  120.  *    expand response files;
  121.  *    do file name glob'bing
  122.  */
  123.     _response(&argc, &argv);
  124.     _wildcard(&argc, &argv);
  125. #endif    /* defined(__EMX__) */
  126.  
  127. /*
  128.  * Set error file stream pointer.
  129.  */
  130.     Efs = stderr;
  131. /*
  132.  * Get library name.
  133.  */
  134.     if ((np = getenv("CAWFLIB")) != NULL)
  135.         lib = np;
  136.     libl = strlen(lib);
  137. /*
  138.  * Get device file name.
  139.  */
  140.     for (ep = getenv("TERM");; ep = NULL) {
  141.         if (ep == NULL || *ep == '\0')
  142.             ep = "dumb";
  143.         l = libl + 1 + strlen(ep) + strlen(".dev") + 1;
  144.         if ((np = malloc(l)) == NULL)
  145.             Error(FATAL, NOLINE,
  146.                 " no string space for device file: ", ep);
  147.         (void) sprintf(np, "%s%s%s.dev", lib,
  148.  
  149. #if    defined(macintosh)
  150.             "",
  151. #else    /* !defined(macintosh) */
  152.             "/",
  153. #endif    /* defined(macintosh) */
  154.  
  155.             ep);
  156.         if (stat(np, &sbuf) == 0)
  157.             break;
  158.         if (strcmp(ep, "dumb") == 0)
  159.             Error(FATAL, NOLINE, " no dumb.dev file in ", lib);
  160.         (void) free(np);
  161.     }
  162.     files[nf++] = np;
  163. /*
  164.  * Get common text file name.
  165.  */
  166.     l = libl + 1 + strlen("common") + 1;
  167.     if ((np = malloc(l)) == NULL)
  168.         Error(FATAL, NOLINE, " no string space for common file name",
  169.             NULL);
  170.     (void) sprintf(np, "%s%scommon", lib,
  171.  
  172. #if    defined(macintosh)
  173.         ""
  174. #else    /* !defined(macintosh) */
  175.         "/"
  176. #endif    /* defined(macintosh) */
  177.  
  178.         );
  179.  
  180.     files[nf++] = np;
  181. /*
  182.  * Process options.
  183.  */
  184.     while ((i = getopt(argc, argv, "c:d:ef:hm:n:o:")) != EOF) {
  185.         switch (i) {
  186.     /*
  187.      * -c c
  188.      *
  189.      * Set the device configuration file path to c.
  190.      */
  191.         case 'c':
  192.             Devconf = optarg;
  193.             break;
  194.     /*
  195.      * -d d
  196.      *
  197.      * Set the output device name to d.
  198.      *
  199.      * The default output device name is NORMAL -- i.e., a device that
  200.      * does bold face with backspace and overprinting and italic face with
  201.      * underscore.  NORMAL is usually a terminal device.
  202.      *
  203.      * There is a built-in device, named ANSI, that does bold face with
  204.      * the ANSI shadow mode and italic face with the ANSI underscore mode.
  205.      * ANSI is normally a terminal device that supports the ANSI shadow
  206.      * and underscore modes.
  207.      *
  208.      * There is a built-in output device, named NONE, that does nothing
  209.      * at all for the bold or italic faces.  This is usually a terminal
  210.      * device.
  211.      *
  212.      * All other device names must match a stanza in the device
  213.      * configuration file.
  214.      */
  215.         case 'd':
  216.             Device = optarg;
  217.             break;
  218.     /*
  219.      * -e -- eject: issue final form feed
  220.      */
  221.         case 'e':
  222.             fff = 1;
  223.             break;
  224.     /*
  225.      * -f f
  226.      *
  227.      * Set f as the font name for the output device (from the device
  228.      * configuration file).
  229.      */
  230.         case 'f':
  231.             Devfont = optarg;
  232.             break;
  233.     /*
  234.      * -h -- display help (usage)
  235.      */
  236.         case 'h':
  237.             help = 1;
  238.             break;
  239.     /*
  240.      * -m m
  241.      *
  242.      * Set the macro file name to m.
  243.      *
  244.      *  Special support is provided for -man, -me and -ms.
  245.      */
  246.         case 'm':
  247.             if (mac) {
  248.                 Error(WARN, NOLINE,
  249.                     "multiple macro file declaration",
  250.                     NULL);
  251.                 break;
  252.             }
  253.             l = libl + 2 + strlen(optarg) + strlen(".mac") + 1;
  254.             if ((np = malloc(l)) == NULL)
  255.                 Error(FATAL, NOLINE, " no string space for ",
  256.                     argv[1]);
  257.             (void) sprintf(np, "%s%sm%s.mac", lib,
  258.  
  259. #if    defined(macintosh)
  260.                 "",
  261. #else    /* !defined(macintosh) */
  262.                 "/",
  263. #endif    /* defined(macintosh) */
  264.  
  265.                 optarg);
  266.  
  267.             files[nf++] = np;
  268.             if (strcmp(optarg, "an") == 0)
  269.                 Marg = MANMACROS;
  270.             else if (strcmp(optarg, "e") == 0)
  271.                 Marg = MEMACROS;
  272.             else if (strcmp(optarg, "s") == 0)
  273.                 Marg = MSMACROS;
  274.             mac++;
  275.             break;
  276.     /*
  277.      * -n n
  278.      *
  279.      * Set the starting page number to n.
  280.      */
  281.         case 'n':
  282.             Thispg = atoi(optarg);
  283.             break;
  284.     /*
  285.      * -o o
  286.      *
  287.      * Set the pages to print list from the string o.
  288.      *
  289.      * Entries are separated by commas.  A range is specified as n-m.
  290.      * A starting range of the form -m has one for a starting value,
  291.      * and a range of the form n- has an ending value equivalent to
  292.      * the end of the document.  For example:
  293.      *
  294.      *    -5,8,10-
  295.      *
  296.      * specifies the printing of pages 1 through 5, 8, and 10 through
  297.      * the end of the document.
  298.      */
  299.         case 'o':
  300.             if (!AsmPgRange(optarg))
  301.                 Error(WARN, NOLINE, "invalid page list: ",
  302.                     optarg);
  303.             break;
  304.     /*
  305.      * Option not recognized by getopt().
  306.      */
  307.         case '?':
  308.             Err = 1;
  309.         }
  310.     }
  311.     if (Defdev())
  312.         Err++;
  313.     if (help || Err) {
  314.       (void) fprintf(stderr,
  315.         "%s %s usage: [-c c] [-d d] [-e] [-f f] [-h] [-m m]\n",
  316.         Pname, Version);
  317.       (void) fprintf(stderr, "\t[-n n] [-o o] file...\n");
  318.       (void) fprintf(stderr,
  319.         "\t-c c      c is the device configuration file path\n");
  320.       (void) fprintf(stderr,
  321.         "\t          (default = %s%s%s)\n", CAWFLIB,
  322.  
  323. #if    defined(macintosh)
  324.         "",
  325. #else    /* !defined(macintosh) */
  326.         "/",
  327. #endif    /* defined(macintosh) */
  328.  
  329.           DEVCONFIG);
  330.       (void) fprintf(stderr,
  331.         "\t-d d      d is the output device name\n");
  332.       (void) fprintf(stderr,
  333.         "\t          (default = NORMAL, using \\b for bold and italic)\n");
  334.       (void) fprintf(stderr,
  335.         "\t          (built-ins = ANSI, NONE and NORMAL)\n");
  336.       (void) fprintf(stderr,
  337.         "\t-e        issue eject after last page\n");
  338.       (void) fprintf(stderr,
  339.         "\t-f f      f is the output device font name\n");
  340.       (void) fprintf(stderr,
  341.         "\t-h        display help (this output)\n");
  342.       (void) fprintf(stderr,
  343.         "\t-m m      m is the macro file name\n");
  344.       (void) fprintf(stderr,
  345.         "\t-n n      n is the starting page number\n");
  346.       (void) fprintf(stderr,
  347.         "\t-o o      o specifies output pages and page ranges\n");
  348.       (void) fprintf(stderr,
  349.         "\tfile ...  source file names\n");
  350.       exit(Err);
  351.     }
  352.     if (mac == 0) {
  353.  
  354.         /*
  355.          * No macros - enable Bold, Italic and Roman fonts.
  356.          */
  357.         for (i = 0; Fcode[i].nm; i++) {
  358.             switch (Fcode[i].nm) {
  359.             case 'B':
  360.             case 'I':
  361.             case 'R':
  362.                 Fcode[i].status = '1';
  363.             }
  364.         }
  365.     }
  366. /*
  367.  * Add user-supplied file names.
  368.  */
  369.     pc = nf;
  370.     if (optind >= argc) {
  371.         files[nf++] = NULL;       /* STDIN */
  372.     } else {
  373.         while (optind < argc) {
  374.             if (nf >= MAXFILES)
  375.                 Error(WARN, NOLINE, " too many files at ",
  376.                     argv[optind]);
  377.             files[nf++] = argv[optind++];
  378.         }
  379.     }
  380. /*
  381.  * Make sure all input files are accessible.
  382.  */
  383.     for (i = 0; i < nf; i++) {
  384.         if (files[i] != NULL) {
  385.             if (stat(files[i], &sbuf) != 0)
  386.                 Error(WARN, NOLINE, " can't find ", files[i]);
  387.         }
  388.     }
  389.     if (Err)
  390.         exit(1);
  391. /*
  392.  * Miscellaneous initialization.
  393.  */
  394.  
  395.     for (i = 0; ; i++) {
  396.         if (Pat[i].re == NULL)
  397.             break;
  398.         if ((Pat[i].pat = regcomp(Pat[i].re)) == NULL)
  399.             Error(WARN, NOLINE, Pat[i].re, " regcomp failure");
  400.     }
  401.     if ((i = Findscale((int)'n', 0.0, 0)) < 0)
  402.         Error(WARN, NOLINE, " can't find Scale['n']", NULL);
  403.     Scalen = Scale[i].val;
  404.     if ((i = Findscale((int)'u', 0.0, 0)) < 0)
  405.         Error(WARN, NOLINE, " can't find Scale['u']", NULL);
  406.     Scaleu = Scale[i].val;
  407.     if ((i = Findscale((int)'v', 0.0, 0)) < 0)
  408.         Error(WARN, NOLINE, " can't find Scale['v']", NULL);
  409.     Scalev = Scale[i].val;
  410.     (void) Findstr((unsigned char *)"CH", (unsigned char *)"= % -", 1);
  411.     Cont = Newstr((unsigned char *)" ");
  412.     Contlen = 1;
  413.     if ((Trtbl = (unsigned char *)malloc(256)) == NULL)
  414.         Error(WARN, NOLINE, " can't allocate translate table space",
  415.             NULL);
  416.     else {
  417.         *Trtbl = ' ';
  418.         for (i = 1; i < 256; i++)
  419.             Trtbl[i] = (unsigned char) i;
  420.     }
  421.     if (Err)
  422.         exit(1);
  423. /*
  424.  * Here begins pass1 of awf - reading input lines and expanding macros.
  425.  */
  426.  
  427. /*
  428.  * Output prolog.
  429.  */
  430.     if (Fstr.i)
  431.         Stringput(Fstr.i, Fstr.il);
  432.     Macro((unsigned char *)".^x");
  433.     Macro((unsigned char *)".^b");
  434.     Macro((unsigned char *)".^# 1 <prolog>");
  435. /*
  436.  * Put today's date in the -me td string or the -ms DY string.
  437.  */
  438.     if (Marg == MEMACROS || Marg == MSMACROS) {
  439.         tm = time(NULL);
  440.         lt = localtime(&tm);
  441.         (void) sprintf(dt, "%s %d, %d",
  442.             Month[lt->tm_mon], lt->tm_mday, lt->tm_year + 1900);
  443.         Findstr(
  444.             (Marg == MEMACROS) ? (unsigned char *)"td"
  445.                        : (unsigned char *)"DY",
  446.             (unsigned char *)dt, 1);
  447.     }
  448. /*
  449.  * Read input files.
  450.  */
  451.     for (i = 0; i < nf; i++) {
  452.         if (files[i] == NULL) {
  453.             np = "stdin";
  454.             Ifs = stdin;
  455.         } else {
  456.  
  457. #if    defined(UNIX)
  458.             if ((Ifs = fopen(files[i], "r")) == NULL)
  459. #else    /* !defined(UNIX) */
  460.             if ((Ifs = fopen(files[i], "rt")) == NULL)
  461. #endif    /* defined(UNIX) */
  462.  
  463.                 Error(FATAL, NOLINE, " can't open ", files[i]);
  464.             np = files[i];
  465.         }
  466.         if (i >= pc) {
  467.             (void) sprintf((char *)Line, ".^# 1 %s", np);
  468.             Macro(Line);
  469.             NR = 0;
  470.         }
  471.         Fsp = 0;
  472.         do {
  473.             while (fgets((char *)Line, MAXLINE, Ifs) != NULL) {
  474.                 NR++;
  475.                 if ((np = strrchr((char *)Line, '\n')) != NULL)
  476.                     *np = '\0';
  477.                 else
  478.                     Line[MAXLINE-1] = '\0';
  479.                 Macro(Line);
  480.             }
  481.             if (i >= pc)
  482.                 Macro((unsigned char *)".^e");
  483.             if (Ifs != stdin)
  484.                 (void) fclose(Ifs);
  485.             if (Fsp > 0) {
  486.                 Free(&Inname);
  487.                 Inname = Inn_stk[Fsp-1];
  488.                 NR = NR_stk[Fsp-1];
  489.                 Ifs = Ifs_stk[Fsp-1];
  490.             }
  491.         } while (Fsp-- > 0);
  492.     }
  493.     Macro(NULL);
  494.     if (fff)
  495.         Charput("\f");
  496.     return(Err);
  497. }
  498.  
  499.  
  500. /*
  501.  * AsmPg(pa, pb) - assemble an ASCII page number
  502.  */
  503.  
  504. char *
  505. AsmPg(pa, pb)
  506.     char *pa;            /* page number in ASCII */
  507.     int *pb;            /* page number in binary */
  508. {
  509.     for (*pb = 0; *pa; pa++) {
  510.         if (*pa < '0' || *pa > '9')
  511.             return(pa);
  512.         *pb = (*pb * 10) + (int)(*pa - '0');
  513.     }
  514.     return(pa);
  515. }
  516.  
  517.  
  518. /*
  519.  * AsmPgRange(s) - assemble a page range
  520.  */
  521.  
  522. int
  523. AsmPgRange(s)
  524.     char *s;            /* page range string */
  525. {
  526.     char *cp, *tbuf;
  527.     int pg, pl, pu;
  528.     struct pgrange *pr;
  529.  
  530.     if (s == NULL || (pl = strlen(s)) == 0)
  531.         return(1);
  532. /*
  533.  * Remove spaces from the range string.
  534.  */
  535.     if ((tbuf = (char *)malloc(pl + 1)) == NULL)
  536.         Error(FATAL, NOLINE, " no string space for page range", NULL);
  537.     for (cp = tbuf; *s; *s++) {
  538.         if (*s != ' ')
  539.             *cp++ = *s;
  540.     }
  541.     *cp = '\0';
  542. /*
  543.  * Parse the range string.
  544.  */
  545.     for (cp = tbuf; *cp;) {
  546.  
  547.     /*
  548.      * Get the starting value.
  549.      * A missing initial range value defaults to one.
  550.      */
  551.         if (*cp == '-')
  552.             pg = 1;
  553.         else
  554.             cp = AsmPg(cp, &pg);
  555.     /*
  556.      * Base further processing on the range terminator character.
  557.      */
  558.         switch (*cp) {
  559.         case ',':        /* single page number */
  560.         case '\0':
  561.             pl = pu = pg;
  562.             break;
  563.         case '-':        /* page number range */
  564.             cp++;
  565.             pl = pg;
  566.         /*
  567.          * Assemble the terminating page number.  A missing
  568.          * number defaults to page 1,000,000 -- the end of
  569.          * the document.
  570.          */
  571.             if (!*cp) {
  572.                 pu = 10000;
  573.                 break;
  574.             }
  575.             cp = AsmPg(cp, &pg);
  576.             pu = pg;
  577.             break;
  578.         default:
  579.             return(0);
  580.         }
  581.     /*
  582.      * Check the page numbers.
  583.      */
  584.         if (pl < 0 || pu < 0 || pl > pu)
  585.             return(0);
  586.         if (*cp) {
  587.             if (*cp != ',')
  588.                 return(0);
  589.             cp++;
  590.         }
  591.     /*
  592.      * Allocate, fill in, and connect a page range structure.
  593.      */
  594.         if ((pr = (struct pgrange *)malloc(sizeof(struct pgrange)))
  595.         == NULL) {
  596.             Error(FATAL, NOLINE, " no space for page range entry",
  597.                 NULL);
  598.         }
  599.         pr->l = pl;
  600.         pr->u = pu;
  601.         pr->next = PgRange;
  602.         PgRange = pr;
  603.     }
  604.     return(1);
  605. }
  606.  
  607.  
  608. /*
  609.  * Macro(inp) - process a possible macro statement
  610.  *        pass non-macros and macros alike to pass 2
  611.  */
  612.  
  613. void
  614. Macro(inp)
  615.     unsigned char *inp;        /* possible macro statement pointer */
  616. {
  617.     unsigned char c[2];        /* characters */
  618.     int endm;            /* end of macro status */
  619.     FILE *fs;            /* temporary file stream */
  620.     int req;            /* request character status */
  621.     unsigned char *s1, *s2;        /* temporary string pointers */
  622.  
  623.     if (inp == NULL) {
  624.         Pass2(NULL);
  625.         return;
  626.     }
  627.     req = (*inp == '.' || *inp == '\'') ? 1 : 0;
  628. /*
  629.  * Check for file name designator.
  630.  */
  631.     if (req && inp[1] == '^' && inp[2] == '#') {
  632.         Free(&Inname);
  633.         Inname = Field(3, inp, 1);
  634.         F = NULL;
  635.         Pass2(inp);
  636.         return;
  637.     }
  638. /*
  639.  * Check for source command - "^[.']so".
  640.  */
  641.     if (req && inp[1] == 's' && inp[2] == 'o') {
  642.         if ((s1 = Field(2, inp, 1)) == NULL) {
  643.             Error(WARN, LINE, " no file specified", NULL);
  644.             return;
  645.         }
  646.         if ((fs = fopen((char *)s1, "r")) == NULL) {
  647.             Error(WARN, LINE, " can't open", NULL);
  648.             return;
  649.         }
  650.         if (Fsp >= MAXFSTK) {
  651.             (void) fclose(fs);
  652.             Error(WARN, LINE, " nesting too deep", NULL);
  653.             return;
  654.         }
  655.         Ifs_stk[Fsp] = Ifs;
  656.         Ifs = fs;
  657.         Inn_stk[Fsp] = Inname;
  658.         Inname = F;
  659.         F = NULL;
  660.         NR_stk[Fsp++] = NR;
  661.         NR = 0;
  662.         return;
  663.     }
  664.  /*
  665.   * Check for start of macro definition.
  666.   */
  667.     if (req && inp[1] == 'd' && inp[2] == 'e') {
  668.         if (inp[3] != ' ' || inp[4] == '\0') {
  669.             Error(WARN, LINE, " illegal macro definition", NULL);
  670.             return;
  671.         }
  672.         c[0] = inp[4];
  673.         c[1] = inp[5];
  674.         Curmx = Findmacro(c, 1);
  675.         return;
  676.     }
  677. /*
  678.  * Check for macro text.  Remove double backslashes.
  679.  */
  680.     if (req && (inp[1] == '\0' || (inp[2] == '\0' && inp[0] == inp[1])))
  681.         endm = 1;
  682.     else
  683.         endm = 0;
  684.     if (Curmx >= 0 && !endm) {
  685.         if (Mtx >= MAXMTXT)
  686.             Error(FATAL, LINE, " out of macro text space", NULL);
  687.         if ((s1 = (unsigned char *)strchr((char *)inp, '\\')) == NULL)
  688.             Macrotxt[Mtx] = Newstr(inp);
  689.         else {
  690.             for (s1 = Pass1ln, s2 = inp;; s1++) {
  691.                 if ((*s1 = *s2++) == '\0')
  692.                     break;
  693.                 if (*s1 == '\\' && *s2 == '\\')
  694.                     s2++;
  695.             }
  696.             Macrotxt[Mtx] = Newstr(Pass1ln);
  697.         }
  698.         if (Macrotab[Curmx].bx == -1)
  699.             Macrotab[Curmx].bx = Mtx;
  700.         Mtx++;
  701.         Macrotab[Curmx].ct++;
  702.         return;
  703.     }
  704. /*
  705.  * Check for end of macro.
  706.  */
  707.     if (Curmx >= 0 && endm) {
  708.         Curmx = -1;
  709.         (void) sprintf((char *)Pass1ln, ".^# %d %s", NR, Inname);
  710.         Pass2(Pass1ln);
  711.         return;
  712.     }
  713.  /*
  714.   * Check for conditionals and macro expansions.
  715.   */
  716.     if (req
  717.     &&  (Findmacro(inp+1, 0) != -1 || regexec(Pat[0].pat, inp))) {
  718.         Expand(inp);
  719.         return;
  720.     }
  721. /*
  722.  * None of the above: forward the line.
  723.  */
  724.     Pass2(inp);
  725. }
  726.